package services

import (
	"context"
	"errors"
	"fmt"
	"sort"
	"time"

	"github.com/google/uuid"

	"github.com/samaa/photosalesplus/backend/internal/models"
	"github.com/samaa/photosalesplus/backend/internal/repositories"
)

const (
	maxOrderQuantity = 99
)

type OrderItemInput struct {
	ProductID uint
	Quantity  int
}

type OrderPreviewItem struct {
	ProductID uint    `json:"product_id"`
	Title     string  `json:"title"`
	UnitPrice float64 `json:"unit_price"`
	Quantity  int     `json:"quantity"`
	Subtotal  float64 `json:"subtotal"`
}

type OrderPreview struct {
	Items       []OrderPreviewItem `json:"items"`
	TotalAmount float64            `json:"total_amount"`
}

type OrderService interface {
	Create(ctx context.Context, userID uint, contact string, items []OrderItemInput) (*models.Order, error)
	Preview(ctx context.Context, userID uint, items []OrderItemInput) (*OrderPreview, error)
	ListForUser(ctx context.Context, userID uint) ([]models.Order, error)
	PurchasedProductIDs(ctx context.Context, userID uint) ([]uint, error)
	CustomerLeaderboard(ctx context.Context, page, limit int) ([]repositories.CustomerLeaderboardEntry, bool, error)
	MerchantOverview(ctx context.Context) (*MerchantOverview, error)
}

type orderService struct {
	orders   repositories.OrderRepository
	users    repositories.UserRepository
	products repositories.ProductRepository
}

func NewOrderService(
	orders repositories.OrderRepository,
	users repositories.UserRepository,
	products repositories.ProductRepository,
) OrderService {
	return &orderService{
		orders:   orders,
		users:    users,
		products: products,
	}
}

func (s *orderService) Create(ctx context.Context, userID uint, contact string, items []OrderItemInput) (*models.Order, error) {
	if len(items) == 0 {
		return nil, errors.New("订单商品列表不能为空")
	}

	preview, username, displayName, err := s.buildPreview(ctx, userID, items)
	if err != nil {
		return nil, err
	}

	order := &models.Order{
		Customer: username,
		Contact:  sanitizeContact(contact, displayName, username),
		Status:   "processing",
	}

	order.OrderNumber = fmt.Sprintf("PS%s", time.Now().Format("20060102")) + uuid.NewString()[:8]

	var orderItems []models.OrderItem
	for _, item := range preview.Items {
		orderItems = append(orderItems, models.OrderItem{
			ProductID: item.ProductID,
			Title:     item.Title,
			Price:     item.UnitPrice,
		})
		for i := 1; i < item.Quantity; i++ {
			orderItems = append(orderItems, models.OrderItem{
				ProductID: item.ProductID,
				Title:     item.Title,
				Price:     item.UnitPrice,
			})
		}
	}
	order.Items = orderItems
	order.TotalAmount = preview.TotalAmount

	if err := s.orders.Create(ctx, order); err != nil {
		return nil, err
	}

	return order, nil
}

func (s *orderService) Preview(ctx context.Context, userID uint, items []OrderItemInput) (*OrderPreview, error) {
	if len(items) == 0 {
		return nil, errors.New("商品列表不能为空")
	}

	preview, _, _, err := s.buildPreview(ctx, userID, items)
	if err != nil {
		return nil, err
	}
	return preview, nil
}

func (s *orderService) ListForUser(ctx context.Context, userID uint) ([]models.Order, error) {
	user, err := s.users.FindByID(ctx, userID)
	if err != nil {
		return nil, err
	}
	return s.orders.ListByCustomer(ctx, user.Username)
}

func (s *orderService) PurchasedProductIDs(ctx context.Context, userID uint) ([]uint, error) {
	user, err := s.users.FindByID(ctx, userID)
	if err != nil {
		return nil, err
	}
	return s.orders.PurchasedProductIDsByCustomer(ctx, user.Username)
}

func (s *orderService) CustomerLeaderboard(ctx context.Context, page, limit int) ([]repositories.CustomerLeaderboardEntry, bool, error) {
	if limit <= 0 {
		limit = 20
	}
	if limit > 50 {
		limit = 50
	}
	if page <= 0 {
		page = 1
	}

	offset := (page - 1) * limit
	rows, err := s.orders.CustomerLeaderboard(ctx, limit+1, offset)
	if err != nil {
		return nil, false, err
	}

	hasMore := len(rows) > limit
	if hasMore {
		rows = rows[:limit]
	}
	return rows, hasMore, nil
}

type MerchantOverview struct {
	Summary      repositories.OrderSummary         `json:"summary"`
	TopProducts  []repositories.ProductSalesDetail `json:"top_products"`
	RecentOrders []models.Order                    `json:"recent_orders"`
	TopCustomers []repositories.CustomerLeaderboardEntry `json:"top_customers"`
}

func (s *orderService) MerchantOverview(ctx context.Context) (*MerchantOverview, error) {
	summary, err := s.orders.Summary(ctx)
	if err != nil {
		return nil, err
	}

	topProducts, err := s.orders.TopProductStats(ctx, 5)
	if err != nil {
		return nil, err
	}

	recentOrders, err := s.orders.Recent(ctx, 5)
	if err != nil {
		return nil, err
	}

	topCustomers, err := s.orders.CustomerLeaderboard(ctx, 5, 0)
	if err != nil {
		return nil, err
	}

	return &MerchantOverview{
		Summary:      summary,
		TopProducts:  topProducts,
		RecentOrders: recentOrders,
		TopCustomers: topCustomers,
	}, nil
}

func (s *orderService) buildPreview(ctx context.Context, userID uint, items []OrderItemInput) (*OrderPreview, string, string, error) {
	user, err := s.users.FindByID(ctx, userID)
	if err != nil {
		return nil, "", "", err
	}

	if user.Role != "" && user.Role != "customer" {
		return nil, "", "", errors.New("当前账号不支持购买")
	}

	normalized := mergeOrderItems(items)
	productIDs := make([]uint, 0, len(normalized))
	for _, item := range normalized {
		productIDs = append(productIDs, item.ProductID)
	}

	pricing, err := s.products.PricingByIDs(ctx, productIDs)
	if err != nil {
		return nil, "", "", err
	}

	if len(pricing) != len(productIDs) {
		return nil, "", "", errors.New("部分商品已下架或不存在，请刷新后重试")
	}

	var previewItems []OrderPreviewItem
	var total float64

	for _, item := range normalized {
		info := pricing[item.ProductID]
		if !info.IsPublished {
			return nil, "", "", fmt.Errorf("商品 %s 已下架，请刷新后重试", info.Title)
		}
		subtotal := info.Price * float64(item.Quantity)
		total += subtotal
		previewItems = append(previewItems, OrderPreviewItem{
			ProductID: item.ProductID,
			Title:     info.Title,
			UnitPrice: info.Price,
			Quantity:  item.Quantity,
			Subtotal:  subtotal,
		})
	}

	sort.Slice(previewItems, func(i, j int) bool {
		return previewItems[i].ProductID < previewItems[j].ProductID
	})

	return &OrderPreview{
		Items:       previewItems,
		TotalAmount: total,
	}, user.Username, user.DisplayName, nil
}

func mergeOrderItems(items []OrderItemInput) []OrderItemInput {
	collapsed := make(map[uint]int)
	for _, item := range items {
		if item.ProductID == 0 {
			continue
		}
		qty := item.Quantity
		if qty <= 0 {
			qty = 1
		}
		if qty > maxOrderQuantity {
			qty = maxOrderQuantity
		}
		collapsed[item.ProductID] += qty
		if collapsed[item.ProductID] > maxOrderQuantity {
			collapsed[item.ProductID] = maxOrderQuantity
		}
	}

	result := make([]OrderItemInput, 0, len(collapsed))
	for id, qty := range collapsed {
		result = append(result, OrderItemInput{
			ProductID: id,
			Quantity:  qty,
		})
	}

	sort.Slice(result, func(i, j int) bool {
		return result[i].ProductID < result[j].ProductID
	})

	return result
}

func sanitizeContact(contact string, displayName string, username string) string {
	value := contact
	if value == "" {
		value = displayName
	}
	if value == "" {
		value = username
	}
	if len(value) > 100 {
		value = value[:100]
	}
	return value
}
